home *** CD-ROM | disk | FTP | other *** search
- ;------------------------------------------------
- ; FSB.ASM -- "File Search and Browse" for OS/2
- ; (c) 1988, Ziff Communications Co.
- ; PC Magazine * Charles Petzold, 3/88
- ;------------------------------------------------
- .286P
- ;-----------------------------------------------------------
- ; Macro to call OS/2 functions without declaring them first
- ;-----------------------------------------------------------
- OS2Call MACRO fnctname
-
- IFNDEF fnctname
- EXTRN fnctname:FAR
- ENDIF
- Call Far Ptr fnctname
-
- ENDM
- ;-----------------------------------
- ; Structures used in OS/2 functions
- ;-----------------------------------
- FileFindBufStr STRUC
- create_date dw ?
- create_time dw ?
- access_date dw ?
- access_time dw ?
- write_date dw ?
- write_time dw ?
- file_size dd ?
- falloc_size dd ?
- attributes dw ?
- string_len db ?
- file_name db 13 dup (?)
- FileFindBufStr ENDS
-
- KeyDataStruc STRUC
- char_code db ?
- scan_code db ?
- status db ?
- nls_shift db ?
- shift_state dw ?
- time dd ?
- KeyDataStruc ENDS
-
- ModeDataStruc STRUC
- md_length dw ?
- md_type db ?
- color db ?
- col dw ?
- row dw ?
- hres dw ?
- vres dw ?
- ModeDataStruc ENDS
- ;--------------------------------
- ; Define all segments and DGROUP
- ;--------------------------------
- _TEXT SEGMENT WORD PUBLIC 'CODE'
- _TEXT ENDS
- _DATA SEGMENT WORD PUBLIC 'DATA'
- _DATA ENDS
- _BSS SEGMENT WORD PUBLIC 'BSS'
- _BSS ENDS
- STACK SEGMENT PARA STACK 'STACK'
- dw 1024 dup (?)
- STACK ENDS
- DGROUP GROUP _DATA, _BSS, STACK
- ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP, ES:DGROUP
- ;--------------------------
- ; Initialized Data Segment
- ;--------------------------
- _DATA SEGMENT
-
- SyntaxMsg db 13, 10, "Syntax: FSB filespec"
- db 13, 10
- db 13, 10, "File Search and Browse "
- db "(c) 1988, Ziff Communications Co."
- db 13, 10, "PC Magazine ", 254," Charles Petzold, 3/88"
- CRLF db 13, 10, 0
-
- DriveError db "FSB: Invalid disk drive", 0
- StartDirError db "FSB: Invalid directory", 0
- FileFindError db "FSB: Invalid file spec", 0
- PipeError db "FSB: Cannot not create pipe", 0
- ThreadError db "FSB: Cannot not create second thread", 0
- FileOpenError db 9, "FSB: Cannot open file for reading", 13, 10, 0
- VideoModeError db 9, "FSB: Unsupported video mode", 13, 10, 0
- RootDir db "\", 0
- Delimiters db 9, ' ,;=', 0
- DoBrowse db 1
-
- _DATA ENDS
- ;----------------------------
- ; Uninitialized Data Segment
- ;----------------------------
- _BSS SEGMENT
-
- FileSpec dw ?, ?
- LastBackSlash dw ?
- PipeReadHandle dw ?
- PipeWriteHandle dw ?
- ThreadID dw ?
- ThreadStack dw 1024 dup (?)
- FullFileName db 80 dup (?)
- BytesRead dw ?
- BytesWritten dw ?
-
- _BSS ENDS
- ;--------------
- ; Code Segment
- ;--------------
- _TEXT SEGMENT
- ;----------------------------------------------
- ; Parse command line to get file specification
- ;----------------------------------------------
- Entry: Push DS ; Data segment selector
- Pop ES ; Transfer it to ES
- Mov DS, AX ; DS = Environment selector
- Mov SI, BX ; SI = Start of command line
-
- SkipProgName: Lodsb ; Pull a command line byte
- Or AL, AL ; Check if it's zero
- Jnz SkipProgName ; If not, continue
-
- SkipDelim: Lodsb ; Get command line byte
- Or AL, AL ; See if it's zero
- Jnz CheckDelim ; If not, check for delimiter
- Jmp DoSyntaxMsg ; If so, display message
-
- CheckDelim: Mov CX, 5 ; Five delimiters
- Mov DI, Offset Delimiters ; pointer to them
- Repne Scasb ; scan for delimiter
- Jz SkipDelim ; if delimiter, loop around
-
- Cmp Byte Ptr [SI], ':' ; Check if a drive present
- Jnz NoDiskDrive ; If not, skip section
-
- And AL, 0DFh ; Capitalize it
- Sub AL, '@' ; Change from A to 1, etc
- Sub AH, AH ; Zero out top byte
-
- Push AX ; Change to that drive
- OS2Call DosSelectDisk ; by calling OS/2
-
- Mov DX, Offset DriveError
- Or AX, AX ; If AX not zero,
- Jnz ErrorExit ; display message and exit
-
- Add SI, 2 ; Skip past drive
- NoDiskDrive: Dec SI ; First character of rest
- Mov ES:[FileSpec], SI ; Save the address
- Mov ES:[FileSpec + 2], DS
- FindEnd: Lodsb ; Get a byte
- Cmp AL, '\' ; Check if it's a backslash
- Jnz NotBackSlash ; If not, continue
-
- Mov ES:[LastBackSlash], SI ; If so, save the address
- NotBackSlash: Mov CX, 6 ; now six delimiters
- Mov DI, Offset Delimiters ; pointer to delimiters
- Repne Scasb ; scan them
- Jnz FindEnd ; if not delimiter, loop around
-
- Mov Byte Ptr [SI-1], 0 ; terminate with zero
- DoChangeDir: Mov SI, ES:[LastBackSlash] ; Address of last back slash
- Or SI, SI ; See if any at all
- Jz NoChangeDir ; If none, skip this section
-
- Dec SI ; Points to last backslash now
- Cmp SI, ES:[FileSpec] ; Check if at beginning
- Jnz ChangeToDir ; If not, use directory
-
- Inc Word Ptr ES:[FileSpec] ; Skip past initial backslash
- Push DGROUP ; Segment of new dir
- Push Offset RootDir ; Offset of new dir
- Jmp Short CallChangeDir ; Change to root directory
-
- ChangeToDir: Mov Byte Ptr [SI], 0 ; Terinate dir name with zero
- Push Word Ptr ES:[FileSpec + 2] ; This is segment
- Push Word Ptr ES:[FileSpec] ; This is offset
- Inc SI ; Save address of filename
- Mov ES:[FileSpec], SI ; in FileSpec
-
- CallChangeDir: Push 0 ; Reserved bytes
- Push 0
- OS2Call DosChdir ; Change directory
-
- Mov DX, Offset StartDirError
- Or AX, AX ; If non-zero return code,
- Jnz ErrorExit ; display message and leave
-
- NoChangeDir: Push ES ; Set DS to data segment
- Pop DS
-
- Call MainRoutine ; Go!
-
- Push 1 ; All threads to terminate
- Push 0 ; Return code
- OS2Call DosExit ; End the program
- ;-------------------------------------
- ; Error Exit: DX is pointer to string
- ;-------------------------------------
- DoSyntaxMsg: Mov DX, Offset SyntaxMsg
- ErrorExit: Mov AX, DGROUP ; Set DS to data segment
- Mov DS, AX
- Mov BX, 2 ; Standard Error handle
- Call StringLen ; Get length of DX string
- Mov CX, AX ; Move it to CX
- Call MyDosWrite ; Display error message
-
- Push 1 ; All threads to terminate
- Push 1 ; Error return code
- OS2Call DosExit ; End the program
- ;----------------------------------------------------------------
- ; Main Routine, create pipe, start second thread, and do browses
- ;----------------------------------------------------------------
- MainRoutine: Push DS ; Address for read handle
- Push Offset PipeReadHandle
- Push DS ; Address for write handle
- Push Offset PipeWriteHandle
- Push 16384 ; Size of pipe
- OS2Call DosMakePipe ; Create it
-
- Mov DX, Offset PipeError
- Or AX, AX ; If non-zero return code,
- Jnz ErrorExit ; depart from program
-
- Push CS ; Address of second thread
- Push Offset SecondThread
- Push DS ; Address for thread ID
- Push Offset ThreadID
- Push DS ; Top of thread stack
- Push Offset ThreadStack + 2048
- OS2Call DosCreateThread ; Create the thread
-
- Mov DX, Offset ThreadError
- Or AX, AX ; Again, if error code,
- Jnz ErrorExit ; get out of this place
-
- StartPipeRead: Mov CX, 80 ; Read 80 chars from pipe
- Mov DX, Offset FullFileName ; Store it here
- ReadPipe: Mov BX, [PipeReadHandle] ; Pipe handle
- Call MyDosRead ; Read it
-
- Cmp [BytesRead], 0 ; Check if read no bytes
- Jz NothingLeft ; If so, pipe is empty
-
- Add DX, [BytesRead] ; Increment destination ptr
- Sub CX, [BytesRead] ; Decrement counter
- Jnz ReadPipe ; If not 80 bytes, read again
-
- Mov DX, Offset FileFindError
- Cmp [FullFileName], 0 ; See if file name present
- Jz ErrorExit ; If not, thread had problem
-
- NoErrFromThread:Mov BX, 1 ; Standard output handle
- Mov DX, Offset FullFileName ; Full file name
- Call StringLen ; Get its length
- Mov CX, AX ; Store in CX
- Call MyDosWrite ; Write to standard output
-
- Mov CX, 2 ; Two bytes
- Mov DX, Offset CRLF ; for carriage ret/line feed
- Call MyDosWrite ; Write that out also
-
- Cmp [DoBrowse], 1 ; See if still doing browse
- Jnz StartPipeRead ; If not, skip the call
-
- Call Browse ; Browse the file
-
- Or AX, AX ; If zero returned, continue
- Jz StartPipeRead
- Cmp AX, -1 ; If -1, Esc pressed -->
- Jz NothingLeft ; terminate gracefully
-
- Cmp AX, Offset VideoModeError
- Jnz ShowBrowseErr ; If video mode error,
- Mov [DoBrowse], 0 ; don't try browse again
- ShowBrowseErr: Mov BX, 2 ; Standard error output
- Mov DX, AX ; Address of error message
- Call StringLen ; Find length
- Mov CX, AX ; and save in CX
- Call MyDosWrite ; Dispay the string
-
- Jmp StartPipeRead ; And get another file name
- NothingLeft: Ret ; Return when all done
- ;--------------------------------------------------------------------------
- ; DosRead and DosWrite routines (BX is handle, DX is buffer, CX is length)
- ;--------------------------------------------------------------------------
- MyDosRead: Push BX ; Input handle
- Push DS ; Segment of buffer
- Push DX ; Offset of buffer
- Push CX ; Number of bytes to write
- Push DS ; Segment for bytes read
- Push Offset BytesRead ; Offset for bytes read
- OS2Call DosRead ; Read
- Ret
-
- MyDosWrite: Push BX ; Output handle
- Push DS ; Segment of buffer
- Push DX ; Offset of buffer
- Push CX ; Number of bytes to write
- Push DS ; Segment for bytes written
- Push Offset BytesWritten ; Offset for bytes written
- OS2Call DosWrite ; Write
- Ret
- ;------------------------------------------------------------
- ; StringLen routine (DS:DX points to string, AX is returned)
- ;------------------------------------------------------------
- StringLen: Push ES ; Save some registers
- Push DI
- Push CX
-
- Push DS
- Pop ES ; Set ES to DS
- Mov DI, DX ; Set DI to address of string
- Mov CX, -1 ; Initialize CX to big number
- Sub AL, AL ; Search for zero
- Repnz Scasb ; Do the scan
- Not CX ; Invert CX
- Dec CX ; Take away one
- Mov AX, CX ; That's the length
-
- Pop CX ; Restore saved registers
- Pop DI
- Pop ES
- Ret
-
- _TEXT ENDS
- ;-----------------------------------------------------------------------
- ;-----------------------------------------------------------------------
- ; SECOND THREAD section to search for files and write to pipe
- ;-----------------------------------------------------------------------
- ;-----------------------------------------------------------------------
- _DATA SEGMENT
-
- BackDir db "..", 0
- StarDotStar db "*.*", 0
-
- _DATA ENDS
-
- _BSS SEGMENT
-
- FileFindBuf FileFindBufStr <>
- FileFindBufLen equ $ - FileFindBuf
- FullPathName Label Byte
- CurrentDisk db ?, ?, ?
- CurrentDir db 64 dup (?)
- CurrDirLen dw ?
- Zeroes db 80 dup (?)
- DriveMap dd ?
-
- _BSS ENDS
- ;---------------------------------------------------------
- ; Second Thread -- Calls FindThem, closes pipe, and exits
- ;---------------------------------------------------------
- _TEXT SEGMENT
-
- SecondThread: Push DS ; Variable to receive
- Push Offset CurrentDisk ; current drive
- Push DS ; Variable to receive
- Push Offset DriveMap ; drive map
- OS2Call DosQCurDisk
-
- Add [CurrentDisk], '@' ; Convert to letter
- Mov [CurrentDisk + 1], ':' ; Follow by colon
- Mov [CurrentDisk + 2], '\' ; and backslash
-
- Call FindThem ; Do the finds
-
- TerminateThread:Push [PipeWriteHandle] ; Close the pipe for writing
- OS2Call DosClose
-
- Push 0 ; Terminate this thread only
- Push 0 ; Result code (ignored)
- OS2Call DosExit
-
- SearchError: Mov BX, [PipeWriteHandle] ; If error,
- Mov DX, Offset Zeroes ; write zeroes to
- Mov CX, 80 ; pipe
- Call MyDosWrite
-
- Jmp TerminateThread ; and terminate
- ;----------------------------------------------------------------
- ; Find Them -- Recursive routine to find files fitting file spec
- ;----------------------------------------------------------------
- FindThem: Enter 4, 0 ; Dir Handle is [BP - 2]
- ; Search Count is [BP - 4]
- ;------------------------------------
- ; Get current directory for printing
- ;------------------------------------
- Mov [CurrDirLen], 64 ; Len for current dir
- Push 0 ; Current disk drive
- Push DS
- Push Offset CurrentDir ; Space for current dir
- Push DS
- Push Offset CurrDirLen
- OS2Call DosQCurDir ; Get current dir
-
- Mov DX, Offset FullPathName ; Find length of it
- Call StringLen
- Cmp AX, 3 ; See if root
- Jz NoMoreSlashes ; If so, skip next part
-
- Mov SI, DX ; Add a slash
- Add SI, AX ; at end of directory
- Mov Byte Ptr [SI], '\'
- Mov Byte Ptr [SI + 1], 0
- Inc AX
- NoMoreSlashes: Mov [CurrDirLen], AX ; Save total length
- ;----------------------
- ; Search for the files
- ;----------------------
- Mov Word Ptr [BP - 2], -1 ; Initial directory Handle
- Mov Word Ptr [BP - 4], 1 ; Search for one file
-
- Push [FileSpec + 2] ; segment of find file name
- Push [FileSpec] ; offset of find file name
- Push SS ; segment of directory handle
- Lea AX, [BP - 2] ; offset of directory handle
- Push AX
- Push 07h ; attribute
- Push DS ; segment of buffer
- Push Offset FileFindBuf ; offset of buffer
- Push FileFindBufLen ; length of buffer
- Push DS ; segment of search count
- Lea AX, [BP - 4] ; offset of search count
- Push AX
- Push 0 ; Reserved
- Push 0
- OS2Call DosFindFirst ; Find first file
-
- FindResult1: Or AX, AX ; See if error
- Jz NoFindError1 ; If not skip next
- Cmp AX, 18 ; See if no more files
- Jz FindAllDone1 ; If so, done with search
- Jmp SearchError ; Process error
-
- NoFindError1: Cmp Word Ptr [BP - 4], 0 ; See if zero files found
- Jz FindAllDone1 ; If so, done with search
-
- Mov BX, [PipeWriteHandle] ; Write drive and
- Mov DX, Offset FullPathName ; directory path
- Mov CX, [CurrDirLen] ; to pipe
- Mov SI, CX
- Call MyDosWrite
-
- Mov DX, Offset FileFindBuf.file_name
- Mov CL, [FileFindBuf.string_len] ; Write file name
- Sub CH, CH ; to pipe
- Add SI, CX
- Call MyDosWrite
-
- Mov DX, Offset Zeroes ; Pad with zeroes
- Mov CX, 80 ; written to pipe
- Sub CX, SI
- Call MyDosWrite
-
- Push [BP - 2] ; Directory Handle
- Push DS ; segment of buffer
- Push Offset FileFindBuf ; offset of buffer
- Push FileFindBufLen ; length of buffer
- Push DS ; segment of count
- Lea AX, [BP - 4] ; offset of count
- Push AX
- OS2Call DosFindNext ; Find next file
-
- Jmp FindResult1 ; Loop around
-
- FindAllDone1: Push [BP - 2] ; directory handle
- OS2Call DosFindClose ; close it
- ;-------------------------------
- ; Now search for subdirectories
- ;-------------------------------
- Mov Word Ptr [BP - 2], -1 ; Initial directory handle
- Mov Word Ptr [BP - 4], 1 ; Search for one directory
-
- Push DS ; segment of spec
- Push Offset StarDotStar ; offset of spec
- Push SS ; segment of handle
- Lea AX, [BP - 2] ; offset of handle
- Push AX
- Push 10h ; attribute (dirs only)
- Push DS ; segment of buffer
- Push Offset FileFindBuf ; offset of buffer
- Push FileFindBufLen ; length of buffer
- Push DS ; segment of count
- Lea AX, [BP - 4] ; offset of count
- Push AX
- Push 0 ; reserved
- Push 0
- OS2Call DosFindFirst ; Find first dir
-
- FindResult2: Or AX, AX ; Check if error
- Jz NoFindError2
- Cmp AX, 18 ; Check if all finished
- Jz FindAllDone2
- Jmp SearchError
-
- NoFindError2: Cmp Word Ptr [BP - 4], 0 ; Check if no dirs found
- Jz FindAllDone2
- Test [FileFindBuf.attributes], 10h ; See if directory
- Jz FindTheNext
- Cmp [FileFindBuf.file_name], '.' ; Exclude '.' and '..'
- Jz FindTheNext
-
- Push DS ; Change the directory
- Push Offset FileFindBuf.file_name
- Push 0
- Push 0
- OS2Call DosChdir
-
- Call FindThem ; Recursive call
-
- Push DS ; Change to '..' directory
- Push Offset BackDir
- Push 0
- Push 0
- OS2Call DosChdir
-
- FindTheNext: Push [BP - 2] ; search handle
- Push DS ; segment of buffer
- Push Offset FileFindBuf ; offset of buffer
- Push FileFindBufLen ; length of buffer
- Push DS ; segment of count
- Lea AX, [BP - 4] ; offset of count
- Push AX
- OS2Call DosFindNext ; Find next directory
-
- Jmp FindResult2
-
- FindAllDone2: Push [BP - 2] ; directory handle
- OS2Call DosFindClose ; close it
-
- Leave
- Ret
- _TEXT ENDS
- ;-----------------------------------------------------------------------
- ;-----------------------------------------------------------------------
- ; BROWSE section to display files after names are read from pipe
- ;-----------------------------------------------------------------------
- ;-----------------------------------------------------------------------
- _DATA SEGMENT
-
- db 'ATTR1='
- Attribute1 db 1Eh ; Attribute for file text
- db 'ATTR2='
- Attribute2 db 4Fh ; Attribute for file name
- db 'SHIFT='
- ShiftHoriz db 8 ; Horizontal shift screen default
- FileOffset dw -1, -1
- Dispatch dw Home, Up, PgUp, Dummy, Left
- dw Dummy, Right, Dummy, EndKey, Down, PgDn
-
- _DATA ENDS
-
- _BSS SEGMENT
-
- ModeData ModeDataStruc <>
- KeyData KeyDataStruc <>
- Buffer db 16384 dup (?)
- BufferMid db 16384 dup (?)
- BufferEnd Label Byte
- ScreenSize dw ?
- ScreenStart dw ?
- EndOfFile dw ?
- HorizOffset dw ?
- RightMargin dw ?
- ScreenAddr Label DWord
- ScreenOff dw ?
- ScreenSeg dw ?
- FileHandle dw ?
- OpenAction dw ?
- NewPointer dd ?
- ScreenSaveSel dw ?
-
- _BSS ENDS
- ;---------------------------
- ; Open the File for reading
- ;---------------------------
- _TEXT SEGMENT
-
- Browse: Mov [FileOffset], -1 ; Initialize these pointers
- Mov [FileOffset + 2], -1
-
- Push DS ; segment of name
- Push Offset FullFileName ; offset of name
- Push DS ; segment for handle
- Push Offset FileHandle ; offset for handle
- Push DS ; segment for 'action'
- Push Offset OpenAction ; offset for 'acton'
- Sub AX, AX
- Push AX ; high size (ignored)
- Push AX ; low size (ignored)
- Push AX ; attribute (ignored)
- Push 1 ; open if file exists
- Push 0A0h ; read only / deny write
- Push AX ; reserved
- Push AX ; reserved
-
- OS2Call DosOpen ; Open File
-
- Or AX, AX ; Check if error
- Jz GotTheFile ; If not, continue
-
- Mov AX, Offset FileOpenError
- Ret
- GotTheFile:
- ;-----------------------------
- ; Get Screen Mode Information
- ;-----------------------------
- Mov [ModeData.md_length], 12 ; length of structure
-
- Push DS ; segment of structure
- Push Offset ModeData ; offset of structure
- Push 0 ; reserved
- OS2Call VioGetMode ; get video mode
-
- Or AX, AX ; See if error (only if
- Jz NotDetached ; program is detached)
- VideoError: Mov AX, Offset VideoModeError
- Ret
-
- NotDetached: Test [ModeData.md_type], 2 ; See if graphics mode
- Jnz VideoError ; If so, do not continue
- Mov AX, [ModeData.col] ; character columns
- Mul [ModeData.row] ; character rows
- Jc VideoError ; Leave if exceeds 64K
- Add AX, AX ; Ditto here
- Jc VideoError
- Mov [ScreenSize], AX ; Save screen size in bytes
-
- Push DS ; Segment for address
- Push Offset ScreenAddr ; Offset for address
- Push DS ; Segment for size
- Push Offset ScreenSize ; Offset for size
- Push 0 ; Reserved
- OS2Call VioGetBuf ; Get logical video buffer
-
- Or AX, AX ; Leave if an error
- Jnz VideoError
- ;---------------------------------------
- ; Allocate memory and save screen in it
- ;---------------------------------------
- Push [ScreenSize] ; Size of segment
- Push DS ; Segment for selector
- Push Offset ScreenSaveSel ; Offset for selector
- Push 0 ; No sharing
- OS2Call DosAllocSeg ; Allocate segment
-
- Or AX, AX ; If error, leave
- Jnz VideoError
-
- Push [ScreenSaveSel] ; Segment for destination
- Sub AX, AX
- Push AX ; Offset for destination
- Push DS ; Segment of screen size
- Push Offset ScreenSize ; Offset of screen size
- Push AX ; Starting row
- Push AX ; Starting column
- Push AX ; Reserved
- OS2Call VioReadCellStr ; Save the screen
-
- Call SetExitList ; Will restore on exit
- ;---------------------------------------
- ; Get keyboard key and decide on action
- ;---------------------------------------
- Call Home ; Read file in
- Mov [ScreenStart],SI ; Set buffer address
- KeyLoop: Push ThreadID ; Don't let the search
- OS2Call DosSuspendThread ; slow down the update
-
- Call UpDateScreen ; Update the screen
-
- Push ThreadID
- OS2Call DosResumeThread ; Let the search resume
-
- GetKey: Push DS ; Segment of structure
- Push Offset KeyData ; Offset of structure
- Push 0 ; Wait for key
- Push 0 ; Reserved
- OS2Call KbdCharIn ; Read key
-
- Mov AL, [KeyData.char_code] ; Get character code
- Cmp AL, ' ' ; A space means do next
- Je SpaceLeave ; file
- Cmp AL,27 ; Check if ESC
- Je EscLeave ; If so, terminate
- Cmp AL, 0E0h ; E0 for enhanced keyboard
- Jz ScanCode ; extended keys
- Or AL, AL ; Check if extended
- Jnz GetKey ; If not, try again
- ScanCode: Mov AL, [KeyData.scan_code] ; Get scan code
- Sub AL,71 ; Subtract Home key value
- Jb GetKey ; If below that, not valid
- Cmp AL,(81 - 71) ; Check if above PgDn
- Ja GetKey ; If so, ignore it
- Sub AH,AH ; Zero out top byte
- Add AX,AX ; Double for word access
- Mov BX,AX ; Offset in dispatch table
- Mov SI,[ScreenStart] ; Set current buffer pointer
- Call [Dispatch + BX] ; Do the call
- Mov [ScreenStart],SI ; Set new buffer pointer
- Jmp KeyLoop ; And update the screen
- ;--------------------------------------------
- ; Terminate -- Restore screen and close file
- ;--------------------------------------------
- SpaceLeave: Call ExitRoutine ; Restore screen
- Call UnsetExitList ; Take away exit list
- Sub AX, AX ; 0 means continue with files
- Ret ; Return
-
- EscLeave: Call ExitRoutine ; Restore screen
- Call UnsetExitList ; Take away exit list
- Mov AX, -1 ; -1 means stop program
- Ret ; Return
- ;-------------------------------------
- ; Exit List Processing for Ctrl-Break
- ;-------------------------------------
- SetExitList: Push 1 ; Set an exit list
- Push CS ; Segment of routine
- Push Offset ExitList ; Offset of routine
- OS2Call DosExitList
- Ret
-
- UnsetExitList: Push 2 ; Unset an exit list
- Push CS ; Segment of routine
- Push Offset ExitList ; Offset of routine
- OS2Call DosExitList
- Ret
-
- ExitRoutine: Push [ScreenSaveSel] ; Segment of saved screen
- Push 0 ; Offset of saved screen
- Push [ScreenSize] ; Length of saved screen
- Push 0 ; Starting row
- Push 0 ; Starting column
- Push 0 ; Reserved
- OS2Call VioWrtCellStr ; Restore screen
-
- Push [FileHandle] ; File handle
- OS2Call DosClose ; Close it
- Ret
-
- ExitList: Call ExitRoutine ; Do exit routine
- Push 3 ; Then continue exiting
- Push 0
- Push 0
- OS2Call DosExitList
- ;---------------------
- ; Cursor Key Routines
- ;---------------------
- Home: Sub BX,BX ; For zeroing out values
- Mov AX,[FileOffset] ; Check if read in file
- Or AX,[FileOffset + 2]
- Mov [FileOffset],BX ; Zero out file address
- Mov [FileOffset + 2],BX
- Mov [HorizOffset],BX ; Zero out horizontal offset
- Mov SI,Offset Buffer ; Reset buffer pointer
- Jz Dummy ; Skip file read if in already
- Mov DX,Offset Buffer ; Area to read file in
- Mov CX,32768 ; Number of bytes to read
- Call FileRead ; Read in file
- Dummy: Ret
-
- Up: Call GetPrevChar ; Get previous char in buffer
- Jc UpDone ; If none available, finish
- UpLoop: Call GetPrevChar ; Get previous char again
- Jc UpDone ; if none, we're done
- Cmp AL,10 ; Check if line feed
- Jnz UpLoop ; If not, try again
- Call GetNextChar ; Get char after line feed
- UpDone: Ret
-
- PgUp: Mov CX,Word Ptr [ModeData.row] ; Number of lines
- Dec CX ; less title line
-
- PgUpLoop: Call Up ; Do UP that many times
- Loop PgUpLoop
- Ret
-
- Left: Mov [HorizOffset],0 ; Reset Horizontal Offset
- Ret
-
- Right: Mov AL,[ShiftHoriz] ; Get places to shift
- Sub AH,AH
- Add [HorizOffset],AX ; Move that many right
- Ret
-
- EndKey: Mov BX,SI ; Save buffer pointer
- Call PgDn ; Go page down
- Cmp BX,SI ; Check if we did so
- Jnz EndKey ; If so, do it again
- Ret
-
- Down: Call GetNextChar ; Get next character
- Jc NoMoreDown ; If no more, we're done
- DownLoop: Call GetNextChar ; Get one again
- Jc UpLoop ; If no more, find prev LF
- Cmp AL,10 ; See if line feed
- Jnz DownLoop ; If not, continue
- NoMoreDown: Ret
-
- PgDn: Mov CX,Word Ptr [ModeData.row] ; Number of lines
- Dec CX ; less title line
-
- PgDnLoop: Call Down ; Do DOWN that many times
- Loop PgDnLoop
- Ret
- ;---------------
- ; Update Screen
- ;---------------
- UpdateScreen: Push ES
-
- Les DI,[ScreenAddr] ; Address of display
- Mov CX,ScreenSize ; Number of bytes in screen
- Shr CX,1 ; Half for number of chars
- Mov AL,' ' ; Will blank screen
- Mov AH,[Attribute1] ; With screen attribute
- Rep Stosw ; Blank it
- Mov CX, [ModeData.col] ; Number of character cols
- Mov DI, [ScreenOff] ; Offset of screen
- Mov SI, Offset FullFileName ; File name
-
- DisplayName: Lodsb ; Get character
- Or AL, AL ; See if end
- Jz EndOfName
- Mov AH, [Attribute2] ; Use second attribute
- Stosw ; Display it
- Loop DisplayName
-
- EndOfName: Mov SI,[ScreenStart] ; Address of data in buffer
- Mov DL, 1 ; Start with second line
- Mov AL, Byte Ptr [ModeData.col] ; Length of row
- Sub AH,AH
- Add AX,[HorizOffset] ; Add Horizontal Offset
- Mov [RightMargin],AX ; That's right display margin
-
- LineLoop: Sub BX,BX ; Column Number
- Mov AL, Byte Ptr [ModeData.col] ; Use Line Length
- Mul DL ; and Line Number
- Add AX,AX ; to recalculate
- Mov DI,AX ; display destination
- Add DI,[ScreenOff] ; Add beginning address
-
- CharLoop: Call GetNextChar ; Get next character
- Jc EndOfScreen ; If no more, we're done
- Cmp AL,13 ; Check for carriage return
- Je CharLoop ; Do nothing if so
- Cmp AL,10 ; Check for line feed
- Je LineFeed ; Do routine if so
- Cmp AL,9 ; Check for tab
- Je Tab ; Do routine if so
- Mov CX,1 ; Just 1 char to display
-
- PrintChar: Cmp BX,[HorizOffset] ; See if we can print it
- Jb NoPrint
- Cmp BX,[RightMargin] ; See if within margin
- Jae NoPrint
- Mov AH,[Attribute1] ; Attribute for display
-
- WriteIt: Stosw ; Write without retrace wait
- NoPrint: Inc BX ; Bump up line counter
- Loop PrintChar ; Do it CX times
- Jmp CharLoop ; Then go back to top
-
- Tab: Mov AX,BX ; Current column number
- And AX,07h ; Take lower three bits
- Mov CX,8
- Sub CX,AX ; Subtract from 8
- Mov AL,' ' ; Will print CX blanks
- Jmp PrintChar
-
- LineFeed: Inc DL ; Next line
- Cmp DL,Byte Ptr [ModeData.row] ; See if down at bottom
- Jb LineLoop ; If not, continue
-
- EndOfScreen: Push 0 ; Offset of buffer
- Push [ScreenSize] ; Size of buffer
- Push 0 ; Reserved
- OS2Call VioShowBuf ; Update the screen
-
- Pop ES ; All done -- leave
- Ret
- ;--------------------------------
- ; Get Next Character from buffer
- ;--------------------------------
- ; (Input is SI pointing to buffer, Returns AL, CY if no more)
-
- GetNextChar: Cmp SI, [EndOfFile] ; See if at end of file
- Jae NoMoreNext ; If so, no more chars
- Cmp SI, Offset BufferEnd ; See if at end of buffer
- Jb CanGetNext ; If not, just get character
-
- Push CX ; Otherwise save registers
- Push DX
- Push DI
- Push ES
- Push DS ; Set ES to DS
- Pop ES ; (could be different)
-
- Mov SI,Offset BufferMid ; Move 2nd buffer half
- Mov DI,Offset Buffer ; to 1st buffer half
- Mov CX,16384
- Sub [ScreenStart],CX ; New buffer pointer
- Rep Movsb ; Move them
- Mov SI,DI ; SI also buffer pointer
- Add [FileOffset],32768 ; Adjust file addr to read
- Adc [FileOffset + 2],0
- Mov DX,Offset BufferMid ; Place to read file
- Mov CX,16384 ; Number of bytes
- Call FileRead ; Read the file
- Sub [FileOffset],16384 ; Now adjust so reflects
- Sbb [FileOffset + 2],0 ; 1st half of buffer
-
- Pop ES ; Get back registers
- Pop DI
- Pop DX
- Pop CX
-
- Jmp GetNextChar ; And try again to get char
- CanGetNext: Lodsb ; Get the character
- And AL, 7Fh
- Stc
- NoMoreNext: Cmc ; So CY set if no more
- Ret
- ;------------------------------------
- ; Get Previous Character from buffer
- ;------------------------------------
- GetPrevChar: Cmp SI,Offset Buffer ; See if at top of buffer
- Ja CanGetPrev ; If not, just get character
- Mov AX,[FileOffset] ; See if at top of file
- Or AX,[FileOffset + 2]
- Jz AtTopAlready ; If so, can't get anymore
-
- Push CX ; Save some registers
- Push DX
- Push ES
- Push DS
- Pop ES
-
- Mov SI,Offset Buffer ; Move 1st half of buffer
- Mov DI,Offset BufferMid ; to 2nd half of buffer
- Mov CX, 16384
- Add [ScreenStart], CX ; New buffer pointer
- Rep Movsb ; Do the move
- Sub [FileOffset], 16384 ; Adjust file addr for read
- Sbb [FileOffset + 2], 0
- Mov DX, Offset Buffer ; Area to read file into
- Mov CX, 16384 ; Number of bytes
- Call FileRead ; Read the file
-
- Pop ES
- Pop DX ; Get back registers
- Pop CX
-
- CanGetPrev: Dec SI ; Move pointer back
- Mov AL,[SI] ; Get the character
- And AL, 7Fh ; Wipe out high byte
- Stc ; CY flag reset for success
- AtTopAlready: Cmc ; CY flag set for no more
- Ret
- ;--------------------------------------------
- ; Read CX bytes from the file into DX buffer
- ;--------------------------------------------
- FileRead: Push AX ; Save some registers
- Push BX
- Mov [EndOfFile], -1 ; Initialize this
-
- Push [FileHandle] ; File handle
- Push [FileOffset + 2] ; New pointer (high)
- Push [FileOffset] ; New pointer (low)
- Push 0 ; Action
- Push DS ; Segment for new pointer
- Push Offset NewPointer ; Offset for new pointer
- OS2Call DosChgFilePtr
-
- Mov BX, [FileHandle] ; Read from the file
- Call MyDosRead
-
- Or AX, AX ; See if error
- Mov AX, [BytesRead]
- Jz NoReadError ; If no error, continue
- Sub AX, AX ; Otherwise read zero bytes
- NoReadError: Cmp AX,CX ; See if 32K has been read
- Je GotItAll ; If so, we're home free
- Add AX,DX ; Otherwise add to buffer addr
- Mov [EndOfFile],AX ; And save as end of file
-
- GotItAll: Pop BX
- Pop AX
- Ret
-
- _TEXT ENDS
- END Entry